﻿// Silang.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
#include <memory>
#include "Temporary.h"
#include "AstNode.h"
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/ManagedStatic.h"
#include <llvm/Support/Signals.h>
#include <llvm/ExecutionEngine/MCJIT.h>  
#include "llvm/ExecutionEngine/Interpreter.h"
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
#include "llvm/ExecutionEngine/JITEventListener.h"
#include <llvm/Support/DynamicLibrary.h>
#include "si_c.h"
#include "AstPackage.h"
#include "modules.h"
#include "utility.h"

extern int yyparse(void);
extern FILE *yyin, *yyout;
extern int yydebug;

bool parse() {
	try {
		yydebug = 0;
		return 0 == yyparse(); /* start the analysis*/
	}
	catch (std::exception e) {
		std::cerr << "Error: " << e.what() << std::endl;
	}
	return false;
}

using namespace llvm;
LLVMContext llvmContext;
std::unique_ptr<Module> module;

AstPackage* currentPackage = new AstPackage();

void execute(char * const *envp){
	char *error = NULL;

	std::string ErrStr;
	llvm::StringRef MCPU = llvm::sys::getHostCPUName();

	std::cout << "MCPU: " << MCPU.str() << std::endl;
	Function *mainFunction = currentPackage->getFunc();

	auto iter=module->functions();
	for( auto i=iter.begin(); i!=iter.end(); i++){
		std::cout << i->getName().str() << std::endl;
	}
	//
	// Execute the program
	//
	llvm::ExecutionEngine *engine = EngineBuilder(std::move(module))
		.setEngineKind(EngineKind::Interpreter)
		.setErrorStr(&ErrStr)
		.setVerifyModules(true)
		.create();

	std::vector<std::string> noargs;
	if (engine){
		CLangModule::moveAll(engine);
		//void* addr = &printf;
		//engine->addGlobalMapping("_printf", (uint64_t)addr);

		//addr=sys::DynamicLibrary::SearchForAddressOfSymbol("createObject");
		//if(addr) engine->addGlobalMapping("_createObject", (uint64_t)addr);

		// engine->finalizeObject();

		

		//engine->runStaticConstructorsDestructors(false);
		engine->runFunctionAsMain(mainFunction, noargs, envp);
		//engine->runStaticConstructorsDestructors(true);
	}
	else
		std::cerr << "无法创建 JIT 引擎: " << ErrStr << std::endl;
	CLangModule::shutdown();
	// llvm::llvm_shutdown();
	// delete engine;
}

using namespace llvm;

int main(int argc, char* argv[],  char * const *envp)
{
	std::string v= encodeByHash("Hello World!");
	std::cout << v << std::endl;
	// sys::PrintStackTraceOnErrorSignal(argv[0]);
	InitializeNativeTarget();
	InitializeNativeTargetAsmPrinter();
	InitializeNativeTargetAsmParser();
	// LLVMInitializeNativeDisassembler();

	auto *m = new Module("TOP", llvmContext);
	module.reset(m);
	make_c_functions(m);

	bool b;
	if (argc > 1) {
		yyin = fopen(argv[1], "r"); /* 首先打开要被处理的文件（参数1）yyin是lex默认的文件输入指针，设置了则不处理控制台输入 */
		if (!yyin) {
			std::cerr << "无法打开文件：" << argv[1] << std::endl;
			return -1;
		}
		b = parse();
		fclose(yyin);
	}
	else {
		b = parse();
	}

	if (b) {
		try {
			currentPackage->preprocessor();
		}
		catch (std::runtime_error e) {
			std::cerr << "发生异常：" << e.what() << std::endl;
			return -1;
		}

		std::ofstream of("out.gv");
		of << "digraph ast {" << std::endl;
		of << "rankdir=LR;" << std::endl;
		currentPackage->draw(of);
		of << "}";
		of.close();

		currentPackage->generateCode(m);

		std::ofstream file("out.ll");
		llvm::raw_os_ostream os(file);
		module->print(os, nullptr, false, true);
		os.flush();
		file.close();
		// system("start out.gv");

		execute(envp);

		// system("lli -force-interpreter out.ll");
	}
	else {
#ifdef _DEBUG
		getchar();
#endif
	}
	return 0;
}

